/*
============================================================================
 Name        : sd_thread.cpp
 Author      : Jian
 Version     :
 Copyright   : GPL
 Description : sd_thread.cpp - source file
============================================================================
*/

/* INCLUDE FILES */
#include "sd_thread.h"
#include "dd_log.h"

#include <e32base.h>	
#include <e32std.h>	

typedef struct {
    int  (*thread_fun)(void*) ;
    void* ptr ;
} CSymThreadData;

static TInt _threadFunction(TAny* aPtr)
{
    CTrapCleanup* cleanupStack = CTrapCleanup::New();
    __DD_ASSERT_DEFENSE(cleanupStack != NULL, return KErrNoMemory);

    CActiveScheduler* activeScheduler = new (ELeave) CActiveScheduler;
    __DD_ASSERT_DEFENSE(activeScheduler != NULL, return KErrNoMemory);

    CActiveScheduler::Install(activeScheduler);

    CSymThreadData* data = (CSymThreadData*)aPtr ;
    int ret = data->thread_fun(data->ptr) ;

    // If we get here, then that means we are ready to start our
    // own active scheduler in this thread.
    // From this point on, the CActiveScheduler::Start() doesn't
    // return until we call CActiveScheduler::Stop().
    //
    // NOTE: active scheduler MUST always have at least one
    // outstanding active object request. Otherwise, active
    // scheduler will hang in the WaitForAnyRequest() method
    // and never handle the call to ActiveScheduler::Stop().
    CActiveScheduler::Start();

    // If we get here, then that means we called CActiveScheduler::Stop()
    // and thread is ready to die.
    delete activeScheduler;
    delete cleanupStack;

    return (ret >= 0) ? KErrNone : KErrGeneral;
}


sd_thread* sd_thread_create(int (*thread_fun)(void*), void* ptr) 
{
    RThread* thread = new RThread() ;
    TBuf<30+1> tmpName ;
    tmpName.Zero() ;
    tmpName.AppendNum((int)thread) ;
    tmpName.Append(_L("-")) ;
    tmpName.AppendNum((int)ptr) ;
    
    CSymThreadData* data = (CSymThreadData*)dd_malloc(sizeof(CSymThreadData));
    __DD_ASSERT_DEFENSE(data, return NULL) ;
    data->thread_fun = thread_fun ;
    data->ptr = ptr ;

    TInt err = thread->Create(tmpName, _threadFunction, 0x8000, NULL, data);
    
    if (err != KErrNone) {
        dd_log_error("create thread error: %d", err) ;
        delete thread ;
        return NULL ;
    }
    
    thread->Resume() ;
    return thread ;
}

void sd_thread_destroy(sd_thread* thread) 
{
    RThread* thrd = (RThread*) thread ;

    __DD_ASSERT_DEFENSE(thrd, return) ;

    thrd->Kill(KErrNone) ;
}

/* End of File */
